package com.simplenix.nicasio.hmaint.util;

import com.simplenix.nicasio.admin.eb.User;
import com.simplenix.nicasio.hmaint.EntityDefinition;
import com.simplenix.nicasio.hmaint.EntityFactory;
import com.simplenix.nicasio.hmaint.HMaintException;
import com.simplenix.nicasio.misc.AppException;
import com.simplenix.nicasio.misc.DateUtil;
import com.simplenix.nicasio.misc.StrUtil;
import com.simplenix.nicasio.persistence.HibernateUtil;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;

/**
 *
 * @author fronald
 */
public class HMaintUtil {

	/**
	 * Process the request and return a Criteria
	 * @return
	 */
	public static Criteria processRequest(HttpServletRequest request, String entityClassName) throws HMaintException {
		EntityDefinition ed = EntityFactory.getInstance().getEntityDefinition(entityClassName);
		Criteria c = HibernateUtil.getCurrentSession().createCriteria(ed.getEntityClass());
		for (String field : ed.getFieldsNames()) {
			String fValue = StrUtil.nvl(request.getParameter(field));
			if (!fValue.equals("")) {
				if (ed.getFieldType(field).equals(EntityDefinition.TYPE_STRING) || ed.getFieldType(field).equals(EntityDefinition.TYPE_TEXT)) {
					c.add(Restrictions.like(field, fValue));
				} else {
					c.add(Restrictions.eq(field, fValue));
				}
			}
		}
		return c;
	}

	public static String getValue(Object o, String fieldName) throws HMaintException {
		EntityDefinition ed = EntityFactory.getInstance().getEntityDefinition(o.getClass());
		try {
			Method m = o.getClass().getDeclaredMethod(ed.getGetterName(fieldName));
			Object rtn = m.invoke(o);
			if (rtn != null) {
				String classType = rtn.getClass().getName();
				if (classType.equals(String.class.getName())) {
					return (String) rtn;
				}
				if (classType.equals(Character.class.getName())) {
					return (String) ((Character) rtn).toString();
				} else if (classType.equals(Integer.class.getName())) {
					return (String) ((Integer) rtn).toString();
				} else if (classType.equals(Long.class.getName())) {
					return (String) ((Long) rtn).toString();
				} else if (classType.equals(BigInteger.class.getName())) {
					return (String) ((BigInteger) rtn).toString();
				} else if (classType.equals(Short.class.getName())) {
					return (String) ((Short) rtn).toString();
				} else if (classType.equals(Float.class.getName())) {
					return (String) ((Float) rtn).toString();
				} else if (classType.equals(Double.class.getName())) {
					return (String) ((Double) rtn).toString();
				} else if (classType.equals(BigDecimal.class.getName())) {
					return (String) ((BigDecimal) rtn).setScale(2, BigDecimal.ROUND_HALF_EVEN).toString();
				} else if (classType.equals(Boolean.class.getName())) {
					return ((Boolean) rtn) ? "Y" : "N";
				} else if (classType.equals(Date.class.getName())) {
					return DateUtil.formatPadrao((Date) rtn);
				}
			} else {
				return "";
			}
			return "";
		} catch (Exception ex) {
			throw new HMaintException(ex);
		}
	}

	public static Map addOrUpdate(Map map, Class entity) throws AppException {
		EntityDefinition def = EntityFactory.getInstance().getEntityDefinition(entity);
		Object o;
		boolean add = true;
		if (map.containsKey(def.getKeyFieldName())) {
			add = false;
			Map keyMap = new HashMap();
			keyMap.put(def.getKeyFieldName(), map.get(def.getKeyFieldName()));
			Criteria c = HibernateUtil.getCurrentSession().createCriteria(entity);
			parseMapFindToCriteria(keyMap, c, entity);
			Object orig = c.uniqueResult();
			o = parseMapToObject(map, entity, orig);
		} else {
			o = parseMapToObject(map, entity);
		}
		try {
			if (add) {
				HibernateUtil.getCurrentSession().save(o);
			} else {
				HibernateUtil.getCurrentSession().merge(o);
			}
		} catch (Exception e) {
			throw new AppException(e);
		}
		return map;
	}

	public static Map delete(Map<String, Object> map, Class entity) throws AppException {
		try {
			Criteria c = HibernateUtil.getCurrentSession().createCriteria(entity);
			parseMapFindToCriteria(map, c, entity);
			List list = c.list();
			for (Object obj : list) {
				boolean cn = true;
				if (obj.getClass().getName().equals(User.class.getName())) {
					User u = (User) obj;
					if (StrUtil.nvl(u.getLogin()).equals("admin")) {
						cn = false;
					}
				}
				if (cn) {
					HibernateUtil.getCurrentSession().delete(obj);
				}
			}
		} catch (Exception e) {
			throw new AppException(e);
		}
		return map;
	}

	public static void parseMapFindToCriteria(Map<String, Object> map, Criteria c, Class entity) throws HMaintException {
		EntityDefinition ed = EntityFactory.getInstance().getEntityDefinition(entity);
		try {
			for (String key : map.keySet()) {
				if (ed.getFieldsNames().contains(key)) {
					Object value = map.get(key);
					value = getObjectAsCorrectType(value, key, entity);
					c.add(Restrictions.eq(key, value));
				}
			}
		} catch (Exception e) {
			throw new HMaintException(e);
		}
	}

	public static Object getObjectAsCorrectType(Object value, String field, Class entity) throws HMaintException, ParseException {
		EntityDefinition ed = EntityFactory.getInstance().getEntityDefinition(entity);
		if (value != null) {
			if (ed.getFieldType(field).equals(EntityDefinition.TYPE_BOOLEAN)) {
				value = StrUtil.nvl((String) value).equalsIgnoreCase("Y") || StrUtil.nvl((String) value).equalsIgnoreCase("YES") || StrUtil.nvl((String) value).equalsIgnoreCase("TRUE") || StrUtil.nvl((String) value).equalsIgnoreCase("T") ? true : false;
			} else if (ed.getFieldType(field).equals(EntityDefinition.TYPE_DATE)) {
				value = DateUtil.parsePadrao((String) value);
			} else if (ed.getFieldType(field).equals(EntityDefinition.TYPE_DATE_TIME)) {
				value = DateUtil.parsePadraoDataHora((String) value);
			} else if (ed.getFieldType(field).equals(EntityDefinition.TYPE_LONG)) {
				value = Long.parseLong((String) value);
			} else if (ed.getFieldType(field).equals(EntityDefinition.TYPE_NUMBER)) {
				value = Double.parseDouble((String) value);
			}
		}
		return value;
	}

	public static Object findById(Class entity, String id) throws HMaintException {
		Map find = new HashMap();
		EntityDefinition ed = EntityFactory.getInstance().getEntityDefinition(entity);
		find.put(ed.getKeyFieldName(), id);
		Criteria c = HibernateUtil.getCurrentSession().createCriteria(entity);
		parseMapFindToCriteria(find, c, entity);
		return c.uniqueResult();
	}

	public static Object parseMapToObject(Map map, Class entity) throws AppException {
		return parseMapToObject(map, entity, null);
	}

	public static Object parseMapToObject(Map map, Class entity, Object originalReg) throws AppException {
		try {
			if (map == null || entity == null) {
				return null;
			}
			Object o = entity.newInstance();
			EntityDefinition def = EntityFactory.getInstance().getEntityDefinition(entity);
			for (String field : def.getFieldsNames()) {
				if (map.containsKey(field)) {
					Object value;
					Method setter = entity.getMethod("set" + StrUtil.capitalize(field), def.getFieldClassType(field));
					if (def.haveDigester(field)) {
						Method digester = entity.getMethod(def.getDigesterForField(field), def.getFieldClassType(field));
						if (originalReg != null) {
							Method getter = entity.getMethod("get" + StrUtil.capitalize(field));
							Object vorig = getter.invoke(originalReg);
							if (vorig == null && map.get(field) == null || (vorig.equals(map.get(field)))) {
								value = vorig;
							} else {
								value = digester.invoke(o, map.get(field));
							}
						} else {
							value = digester.invoke(o, map.get(field));
						}
					} else {
						value = map.get(field);
					}
					if (value instanceof String) {
						value = getObjectAsCorrectType(value, field, entity);
					}
					setter.invoke(o, value);
				}
			}
			return o;
		} catch (Exception e) {
			throw new AppException(e);
		}
	}

}
